package am.fp
{
  import flash.display.Stage;
  import flash.text.TextField;
  import flash.ui.Keyboard;
  import flash.events.KeyboardEvent;
  
  import am.fp.FPDispatcher;
  import am.fp.events.*;  

  /**
   * Handle keyboard shortcuts.
   *
   * Currently available shortcuts are:
   * Ctrl-C : copy selected text
   * Ctrl-F : show/hide search pane
   * Ctrl-P : show/hide print pane
   * Ctrl-T : show/hide tiles pane
   * T : switch to the Text selection mode
   * H : switch to the grab Hand mode
   * HOME : scroll to beginning
   * END : scroll to end
   * arrow keys : vertical/horizontal scrolling
   * PAGE UP/DOWN : vertical scrolling page by page
   * + : zoom +
   * - : zoom -
   */
  public class KeyboardManager
  {
    protected static var m_instance: KeyboardManager;
    protected var m_stage: Stage;
    
    public function KeyboardManager(enforcer: SingletonEnforcer)
    {
      if (enforcer == null)
        throw new Error("This class is a singleton so it can't be instantiated");
    }
    
    public static function get instance(): KeyboardManager
    {
      if (m_instance == null)
        m_instance = new KeyboardManager(new SingletonEnforcer);
      return m_instance;
    }
    
    public function enable(stage: Stage = null): void
    {
      if (stage)
        m_stage = stage;
      else if (!m_stage)
        return;
      m_stage.addEventListener(KeyboardEvent.KEY_UP, onKeyboardUp, false, 0, true);
      m_stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyboardDown, false, 0, true);
    }
    
    public function disable(): void
    {
      if (m_stage)
      {
        m_stage.removeEventListener(KeyboardEvent.KEY_UP, onKeyboardUp, false);
        m_stage.removeEventListener(KeyboardEvent.KEY_DOWN, onKeyboardDown, false);
      }
    }

    /**
     * Key up handler.
     */
    protected function onKeyboardUp(e: KeyboardEvent): void
    {
      if (m_stage.focus && !(e.target is TextField))
      {
        if (e.ctrlKey)  // Control key is pressed
        {
          switch (e.keyCode)
          {
            case 67:  // Ctrl-C : copy selected text
              FPDispatcher.instance.dispatchEvent(new TextSelectionEvent(TextSelectionEvent.SET_CLIPBOARD));
            break;

            case 70:  // Ctrl-F : show/hide search pane
              FPDispatcher.instance.dispatchEvent(new SidePaneEvent(SidePaneEvent.TOGGLE, SidePaneEvent.PANE_SEARCH));
            break;

            case 80:  // Ctrl-P : show/hide print pane
              FPDispatcher.instance.dispatchEvent(new SidePaneEvent(SidePaneEvent.TOGGLE, SidePaneEvent.PANE_PRINT));
            break;

            case 84:  // Ctrl-T : show/hide tiles pane
              FPDispatcher.instance.dispatchEvent(new SidePaneEvent(SidePaneEvent.TOGGLE, SidePaneEvent.PANE_TILES));
            break;
          }
        }
        else
        {
          switch (e.keyCode)
          {
            case 84: // T : switch to the Text selection mode
              FPDispatcher.instance.dispatchEvent(new ModeEvent(ModeEvent.CHANGE, ModeEvent.MODE_TEXT));
            break;

            case 72: // H : switch to the grab Hand mode
              FPDispatcher.instance.dispatchEvent(new ModeEvent(ModeEvent.CHANGE, ModeEvent.MODE_GRAB));
            break;

            case Keyboard.HOME: // scroll to beginning
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.HOME));
            break;

            case Keyboard.END: // scroll to end
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.END));
            break;
          }
        }
      }
    }
    
    /**
     * Key down handler.
     */
    protected function onKeyboardDown(e: KeyboardEvent): void
    {
      if (m_stage.focus && !(e.target is TextField))
      {
        switch (e.charCode)
        {
          case 43:  // + : zoom +
            FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.ZOOM_PLUS));
          break;
          
          case 45: // - : zoom -
            FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.ZOOM_MINUS));
          break;
          
          default:
          switch (e.keyCode)
          {
            // vertical scroll 
            case Keyboard.DOWN:
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.DOWN));
            break;

            case Keyboard.UP:
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.UP));
            break;

            case Keyboard.PAGE_DOWN:
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.PAGE_DOWN));
            break;

            case Keyboard.PAGE_UP:
            FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.PAGE_UP));
            break;

            // horizontal scroll 
            case Keyboard.RIGHT:
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.RIGHT));
            break;

            case Keyboard.LEFT:
              FPDispatcher.instance.dispatchEvent(new ScrollPageEvent(ScrollPageEvent.SCROLL, ScrollPageEvent.LEFT));
            break;
            
            // zoom
            case Keyboard.NUMPAD_ADD:
              FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.ZOOM_PLUS));
            break;

            case Keyboard.NUMPAD_SUBTRACT:
              FPDispatcher.instance.dispatchEvent(new ZoomEvent(ZoomEvent.ZOOM_MINUS));
            break;
          }
        }
      }
    }
  }
}

class SingletonEnforcer {}
